﻿package components 
{
	import com.bit101.components.Component;
	import com.bit101.components.Panel;
	import com.bit101.components.VSlider;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFieldAutoSize;
	/**
	 * ...
	 * @author s
	 */
	public class ListBox extends Component
	{
		private var _items:Vector.<String>;
		private var _highlightedItemMap:Vector.<Boolean>;
		private var _key2itemIndex:Object;
		private var _text2key:Object;
		
		private var _rows:Vector.<TextField>;
		private var _rowsContainer:Sprite;
		private var _mask:Sprite;
		private var _scrollbar:VSlider;
		private var _cursor:Sprite;
		
		private var _autoScrollStartPos:int;
		private var _autoScrollEndPos:int;
		private var _autoScrollMotionCt:int;
		private var _autoScrollMotionMax:int;
		private var _inAutoScroll:Boolean;

		private var _nrows:int;
		private static const Y_MARGIN:int = 4;
		private static const X_MARGIN:int = 4;
		private static const TEXT_HEIGHT:int = 10;
		public static const ITEM_HEIGHT:int = TEXT_HEIGHT + Y_MARGIN;

		private static const TEXT_HIGHLIGHT_COLOR:int = 0x0066FF;
		private static const TEXT_UNHIGHLIGHT_COLOR:int = 0x404040;
		private static const TEXT_FORMAT:TextFormat = new TextFormat("ＭＳ Ｐゴシック", TEXT_HEIGHT);

		public function ListBox(parent:Sprite, x:int, y:int, width:int, nrows:int) 
		{
			var i:int;
			
			super(parent, x, y);
			super.width = width;
			super.height = ITEM_HEIGHT * nrows;

			_items = new Vector.<String>;
			_key2itemIndex = new Object;
			_text2key = new Object;
			_highlightedItemMap = new Vector.<Boolean>;
			_inAutoScroll = false;
			
			_mask = new Sprite;
			this.addChild(_mask);
			_mask.x = _mask.y = 0;
			_mask.graphics.clear();
			_mask.graphics.beginFill(0x101010, 0.6);
			_mask.graphics.drawRect(0, 0, super.width, super.height);
			_mask.graphics.endFill();
			
			_rowsContainer = new Component(this, 0, 0);
			_rowsContainer.width = this.width;
			_rowsContainer.height = this.height;
			_rowsContainer.mask = _mask;
			
			_scrollbar = new VSlider(this, this.width, 0, onScroll)
			_scrollbar.x = this.width - _scrollbar.width;
			_scrollbar.height = this.height;
			_scrollbar.minimum = 0;
			_scrollbar.maximum = 0;
			
			_cursor = new Sprite;
			this.addChild(_cursor);
			
			_nrows = nrows;
			_rows = new Vector.<TextField>;
			for (i = 0; i < _nrows + 1; i++) {
				var tf:TextField = new TextField;
				_rowsContainer.addChild(tf);
				tf.autoSize = TextFieldAutoSize.NONE
				tf.width = this.width - _scrollbar.width - X_MARGIN * 2;
				tf.mouseEnabled = true;
				tf.textColor = TEXT_UNHIGHLIGHT_COLOR;
				tf.x = X_MARGIN;
				tf.y = ITEM_HEIGHT * i;
				tf.text = "";
				tf.selectable = false;
				tf.setTextFormat(TEXT_FORMAT);
				tf.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverToItem);
				tf.addEventListener(MouseEvent.MOUSE_OUT,  onMouseOutFromItem);
				tf.addEventListener(MouseEvent.CLICK,      onClickItem); 
				//tf.mask = this;
				//tf.mask = _mask;
				_rows.push(tf);
			}
		}

		public function updateContents():void 
		{
			var i:int;
			var topIndex:int = topPos / ITEM_HEIGHT
			var offset:int = topPos % ITEM_HEIGHT;
			
			for (i = 0; i < _nrows + 1; i++) {
				if (i + topIndex >= _items.length) {
					break;
				}
				_rows[i].textColor = _highlightedItemMap[i + topIndex] ?
										TEXT_HIGHLIGHT_COLOR :
										TEXT_UNHIGHLIGHT_COLOR;
				_rows[i].text = _items[i + topIndex];
				_rows[i].y = ITEM_HEIGHT * i - offset;
			}
		}

		public function push(text:String, key:String = null):void 
		{
			_items.push(text);
			_highlightedItemMap.push(false);
			if(key != null){
				_key2itemIndex[key] = _items.length - 1;
				_text2key[text] = key;
			}
			syncScrollbarSizeToItems();
			updateContents();
		}

		public function unshift(text:String, keyStr:String = null):void 
		{
			for (var key:String in _key2itemIndex) {
				_key2itemIndex[key]++;
			}
			_items.unshift(text);
			_highlightedItemMap.unshift(false);
			
			if (keyStr != null) {
				_key2itemIndex[keyStr] = 0;
				_text2key[text] = keyStr;
			}
			syncScrollbarSizeToItems();
			updateContents();
		}
		
		private function syncScrollbarSizeToItems():void 
		{
			var top:int = topPos;
			_scrollbar.maximum = Math.max(_items.length - _nrows, 0) * ITEM_HEIGHT;
			this.topPos = top;
		}

		public function focusItem(key:String):void 
		{
			if (!_inAutoScroll && _key2itemIndex[key] != undefined) {
				var index:int = _key2itemIndex[key] as int;
				_autoScrollStartPos = topPos;
				_autoScrollEndPos = Math.max(index - _nrows / 2 + 0.5, 0) * ITEM_HEIGHT;
				_autoScrollMotionCt = 0;
				_autoScrollMotionMax = 16;
				this.addEventListener(Event.ENTER_FRAME, onEnterFrameForAutoScroll);
				_inAutoScroll = true;
			}
		}

		public function highlightItem(key:String):void 
		{
			if (_key2itemIndex[key] != undefined) {
				_highlightedItemMap[_key2itemIndex[key] as int] = true;
			}
		}

		public function unhighlightAll():void 
		{
			for (var i:int = 0; i < _highlightedItemMap.length; i++) {
				_highlightedItemMap[i] = false;
			}
		}

		
		// event listener
		private function onEnterFrameForAutoScroll(e:Event):void 
		{
			var d:Number = (1 - Math.cos(Math.PI * _autoScrollMotionCt / _autoScrollMotionMax)) / 2.0;
			if (_autoScrollMotionCt < _autoScrollMotionMax) {
				topPos = _autoScrollStartPos + d * (_autoScrollEndPos - _autoScrollStartPos);
				_autoScrollMotionCt++;
			}
			else {
				_inAutoScroll = false;
				topPos = _autoScrollEndPos;
				removeEventListener(Event.ENTER_FRAME, onEnterFrameForAutoScroll);
			}
			updateContents();
		}

		private function onScroll(e:Event):void 
		{
			updateContents();
		}
		
		private function onMouseOverToItem(e:Event):void 
		{
			var target:TextField = e.target as TextField;
			
			_cursor.graphics.clear();
			_cursor.graphics.lineStyle(1, 0x000000, 0.5);
			_cursor.graphics.moveTo(0, 0);
			_cursor.graphics.lineTo(Math.min(target.textWidth, target.width),0);
			
			_cursor.x = target.x;
			_cursor.y = target.y + target.textHeight + 1;
		}
			
		
		private function onMouseOutFromItem(e:Event):void 
		{
			_cursor.graphics.clear();
		}
		
		private function onClickItem(e:Event):void 
		{
			var item:TextField = e.target as TextField;
			trace(item.text);
		}
		
		
		// properties
		public function get topPos():int
		{
			return _scrollbar.maximum - _scrollbar.value;
		}
		
		public function set topPos(val:int):void 
		{
			_scrollbar.value = _scrollbar.maximum - val;
		}
		
		public function get inAutoScroll():Boolean 
		{
			return _inAutoScroll;
		}
	}

}